/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦，本文采用木兰宽松许可证第2版]
 * 
 * https://zhiqim.org/project/zhiqim_components/zhiqim_upload_large.htm
 *
 * Zhiqim UploadLarge is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.uploadlarge;

import java.io.File;

import org.zhiqim.httpd.context.ServiceExecutor;
import org.zhiqim.httpd.context.ZmlBootstrap;
import org.zhiqim.kernel.Global;
import org.zhiqim.kernel.constants.SignConstants;
import org.zhiqim.kernel.schedule.Day;
import org.zhiqim.kernel.schedule.Scheduler;
import org.zhiqim.kernel.util.Asserts;
import org.zhiqim.kernel.util.Classes;
import org.zhiqim.kernel.util.Files;
import org.zhiqim.kernel.util.Strings;
import org.zhiqim.kernel.util.Validates;

/**
 * 大文件上传引导类
 *
 * @version v1.0.0 @author zouzhigang 2018-11-23 新建与整理
 */
public class ZulBootstrap extends ZmlBootstrap implements ZulConstants, SignConstants
{
    private Scheduler scheduler;
    private boolean self;
    private static Day day;
    
    private String uploadRootDir;
    private String oldRootDir;
    private String accessUrl;
    private ZulCallback callback;
    
    /*******************************************************************************/
    //初始化&销毁
    /*******************************************************************************/
    
    @Override
    public void initBefore() throws Exception
    {
        //1.把本对象加入到上下文中方便找到该类
        context.setAttribute(ZulBootstrap.class, this);
        
        //2.在配置加载之后,把/service/uploadlarge和/service/upll/*加到服务中
        ServiceExecutor executor = context.getServiceExecutor();
        executor.addService(_PATH_SERVICE_UPLOAD_LARGE_, new ZulService());
        executor.addService(_PATH_SERVICE_UPLOAD_LARGE_ACCESS_, new ZulAccess());
        
        //3.增加定时任务清理上传文件碎片表
        if (day == null)
        {//有可能是多个上下文环境都使用了该组件，只取第一个组件设置任务
            self = true;
            day = new Day(new ZulTask(), 5, 7, 7);
            scheduler = Global.getc(Scheduler.class);
            scheduler.addTask(day);
        }
    }
    
    @Override
    protected void initAfter() throws Exception
    {
        //1.读取大文件上传根目录配置
        String rootDir = context.getAttributeString(_SERV_UPLOAD_LARGE_ROOT_DIR_);
        if (Validates.isEmptyBlank(rootDir) || !Files.mkDirectory(rootDir))
        {
            throw Asserts.exception("未配置大文件上传根目录[%s]，或配置的不是一个目录", _SERV_UPLOAD_LARGE_ROOT_DIR_);
        }
        
        uploadRootDir = Files.toLinuxPath(new File(rootDir).getCanonicalPath());
        uploadRootDir = Strings.addEndsWith(uploadRootDir, "/");
        
        //2.读取大文件上传老根目录配置
        String oldDir = context.getAttributeString(_SERV_UPLOAD_LARGE_OLD_DIR_);
        if (Validates.isNotEmptyBlank(oldDir) && Files.exists(oldDir))
        {//存在
            oldRootDir = Files.toLinuxPath(new File(oldDir).getCanonicalPath());
            oldRootDir = Strings.addEndsWith(oldDir, "/");
        }
        
        //3.访问跳转URL
        accessUrl = context.getAttributeString(_SERV_UPLOAD_LARGE_ACCESS_);
        
        //4.读取大文件上传在业务处理后回调类
        String callbackClass = context.getAttributeString(_SERV_UPLOAD_LARGE_CALLBACK_);
        if(Validates.isEmptyBlank(callbackClass))
        {//支持未配置的取缺省不处理
            callback = new ZulCallbackDefault();
        }
        else
        {//有配置的检查是否实现接口
            Object obj = Classes.newInstance(callbackClass);
            if (obj == null || obj instanceof ZulCallback)
            {
                throw Asserts.exception("配置大文件上传回调类[%s][%s]不正确，或未实现回调接口", _SERV_UPLOAD_LARGE_CALLBACK_, callbackClass);
            }
            callback = (ZulCallback)obj;
        }
    }
    
    @Override
    public void destroy()
    {
        if (self)
        {//由自己创建的，结束时清除
            scheduler.removeTask(day);
        }
    }
    
    /*********************************************************************************************/
    //获取参数
    /*********************************************************************************************/
    
    public String getUploadRootDir()
    {
        return uploadRootDir;
    }
    
    public String getOldRootDir()
    {
        return oldRootDir;
    }
    
    public String getFileCanonicalPath(String fileRelativePath)
    {
        fileRelativePath = Strings.removeStartsWith(fileRelativePath, "/");
        String filePath = uploadRootDir + fileRelativePath;
        
        if (oldRootDir == null)
        {//如果没有配置旧根目录，则直接返回当前地址
            return filePath;
        }
        
        //否则判断是否是新地址迁移过来，存在取新地址，不存在返回旧地址
        return Files.isFile(filePath)?filePath:oldRootDir + fileRelativePath;
    }
    
    public ZulCallback getCallback()
    {
        return callback;
    }
    
    public String getAccessUrl()
    {
        return accessUrl;
    }
}
